package com.modestmaps.core
{
	// This class is an extension to the modestmaps mapping API version 1.0 for Actionscript 3.
	// see http://www.modestmaps.com for details on the modestmaps API.
	// 4/24/08 Jay Wood  / San Diego Union-Tribune
	
	import com.modestmaps.Map;
	import com.modestmaps.extras.PolylineOverlay;
	
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.*;

	/**
	 * Draws a marker within a PolylineOverlay on the map. 
	 * <p>
	 * Marker consists of a title string and a sub-title string. The marker text is auto-scaled 
	 * to fit within the bounding box of the containing PolylineOverlay. The text size ranges 
	 * from the specified minimum to the specified maximum font size, always selecting 
	 * the largest font that will fit withing the bounding box.</p> 
	 * <p>
	 * "Bounding Box" refers to a rectangle that circumscribes the PolylineOverlay, 
	 * or that portion of the overlay that is currently visible on screen. 
	 * The marker also is auto-centered vertically and horizontally within that bounding box. 
	 * </p>
 	 * @see http://www.modestmaps.com the official ModestMaps site
	 * @see com.modestmaps.extras.Overlay Overlay
 	 * @see com.modestmaps.extras.PolylineOverlay PolylineOverlay
	 * @see com.modestmaps.Map Map
	 */
	public class PolylineMarker extends Sprite {
		// min and max size limits for title and subtitle re-sizing
		/** 
		 * Specifies the minimum displayable size of the title text for auto-scaling.
		 * Default value=20.
		 */
		public var minTitleSize:uint = 10;
		/** 
		 * Specifies the maximum displayable size of the title text for auto-scaling.
		 * Default value=10.
		 */
		public var maxTitleSize:uint = 20;
		/** 
		 * Formatter for the title text.
		 * Default value = 20 point Arial white.
		 */
		public var titleFormat:TextFormat = new TextFormat("Arial", 20, 0xFFFFFF, true);
		/** 
		 * Formatter for the sub-title text.
		 * Default value = 18 point Arial white.
		 */
		public var subTitleFormat:TextFormat = new TextFormat("Arial", 18, 0xFFFFFF, true);
		
		private var region:PolylineOverlay;
		private var theMap:Map;
				
		// store the text fields and their content-strings
		private var title:TextField;	
		private var subTitle:TextField;
		private var _titleText:String;
		private var _subTitleText:String;
		
		/**
		 * Construct a new PolylineMarker instance with the specified title and subTitle,
		 * for the specified PolylineOverlay and Map.
		 * @param title is the text to be drawn as the top line of the marker.
		 * @param subTitle is the text to be drawn as the second line of the marker. 
		 * @param region is a handle on the PolylineOverlay where this marker is to be drawn.
		 * @param theMap is a handle on the map where this marker is to be drawn.
		 */
		public function PolylineMarker(titleText:String, subTitleText:String, 
			region:PolylineOverlay,theMap:Map) 
		{
			super();
			// create textfields for title and subTitle, and add to the display list
			title = new TextField();
			subTitle = new TextField();
			addChild(title);
			addChild(subTitle);
			// save handles to the region (overlay) and map
			this.region	= region;
			this.theMap = theMap;
			// save the title and subTitle text
			_titleText = titleText;
			_subTitleText = subTitleText;			
			// set properties of title and subTitle
			title.selectable = title.mouseEnabled = title.background = false;
			subTitle.selectable = subTitle.mouseEnabled = subTitle.background = false;
			mouseEnabled = false;
		}
		
		/** returns the title text of this marker */
		public function get titleText():String { return _titleText; }
		
		/** returns the sub-title text of this marker */
		public function get subTitleText():String { return _subTitleText; }
		
		
		/** @private */
		public function redraw():void
		{
			if (!visible) return; // don't waste time if it's not visible
			
			// get bounding rectangle of the label's polygon overlay, in stage coordinates
			var vRect:Rectangle = region.visibleRect;

			// scale down the text for best fit in visible bounding rectangle
			for (var textSize:uint=maxTitleSize; textSize>minTitleSize; textSize-=2)
			{
				titleFormat.size = textSize;
				subTitleFormat.size = textSize-2;
			    title.defaultTextFormat = titleFormat;
	            subTitle.defaultTextFormat = subTitleFormat; 
 				title.text = _titleText;
				subTitle.text = _subTitleText;
 
				// determine max width of headline and data, resize if needed
				var txtWidth:int = Math.max(subTitle.textWidth, title.textWidth)+10;
				var txtHeight:int = title.textHeight + subTitle.textHeight + 5;
				if (txtWidth < vRect.width && txtHeight < vRect.height) break;
			}

			// if the text is shrunk to minimum value, make it invisible
			if (textSize <= minTitleSize) {
				title.visible = subTitle.visible = false;
				return;
			} else {
				title.visible = subTitle.visible = true;
			}

			// set text field sizes based on final text sizes selected
			prepTextField(title);
			prepTextField(subTitle);

			// center text on region's centroid
			title.x = -title.width/2;
			title.y = -title.height;
			subTitle.x = -subTitle.width/2;
			subTitle.y = title.y + title.height;

			// adjust text position if it is off-screen
			adjustTextPositions(vRect);
 		}

		// adjust the title and subtitle textfield positions to fall within 
		// the visible region of the overlay (e.g., after pan and zoom).
		private function adjustTextPositions(vRect:Rectangle):void
		{
			// get visible (on-stage) portion of the polygon bounding rectangle, in stage coordinates
			var sRect:Rectangle = region.stageRect;

			// get boundaries of text block
			var left:int = Math.min(title.x, subTitle.x);
			var width:int = Math.max(title.width, subTitle.width);
			var top:int = title.y - title.height;
			var height:int = title.height+subTitle.height;
			
			// get text boundaries in global coordinates
			var tl:Point = localToGlobal(new Point(left,top));
			var br:Point = localToGlobal(new Point(left+width,top+height));
			
			if (tl.x < vRect.x) 
			// move text right if clipped on left
			{
				title.x = vRect.x - tl.x - title.width/2 + 5;
				subTitle.x = vRect.x - tl.x - subTitle.width/2 + 5;
			} else if (br.x > vRect.right) {
			// move text left if clipped on right
				title.x = vRect.right - br.x - title.width/2 - 5;
				subTitle.x = vRect.right - br.x - subTitle.width/2 - 5;
			}

			if (tl.y < vRect.y)
			// move text down if clipped on top
			{
				title.y += vRect.y - tl.y + 5;
				subTitle.y = title.y + title.height;
			} 
			else if (br.y > vRect.bottom) 
			{
			// move text up if clipped on bottom
				title.y += vRect.bottom - br.y;
				subTitle.y = title.y + title.height;
			}
		}
		
		private function prepTextField(fld:TextField):void {
			fld.width = fld.textWidth+5;
			fld.height = fld.textHeight+5;
		}			

		/** @private -- redraw the marker after resizing map */
		public function resize():void
		{
			redraw();
		}
	}
}
